#include "hashset.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>

void HashSetNew(hashset *h, int elemSize, int numBuckets,
		HashSetHashFunction hashfn, HashSetCompareFunction comparefn, HashSetFreeFunction freefn)
{
  assert(elemSize > 0);
  assert(numBuckets > 0);
  assert(hashfn != NULL);
  assert(comparefn != NULL);

  h->numBuckets = numBuckets;
  h->elemSize = elemSize;
  h->hashFunc = hashfn;
  h->cmpFunc = comparefn;
  h->freeFunc = freefn;
  h->vectorArray = (vector *)malloc(numBuckets * sizeof(vector));
  for (int i = 0; i < numBuckets; ++i)
	  VectorNew(&h->vectorArray[i], h->elemSize, h->freeFunc, 0);
}

void HashSetDispose(hashset *h)
{
  for (int i = 0; i < h->numBuckets; ++i)
    VectorDispose(&h->vectorArray[i]);
}

int HashSetCount(const hashset *h)
{ 
  int n = 0;
  for (int i = 0; i < h->numBuckets; ++i)
	  n += VectorLength(&h->vectorArray[i]);

  return n;
}

void HashSetMap(hashset *h, HashSetMapFunction mapfn, void *auxData)
{
  assert(mapfn != NULL);
  for (int i = 0; i < h->numBuckets; ++i)
      VectorMap(&h->vectorArray[i], mapfn, auxData);
}

void HashSetEnter(hashset *h, const void *elemAddr)
{
  assert(elemAddr != NULL);
  int hash = h->hashFunc(elemAddr, h->numBuckets);
  assert(hash >= 0 && hash < h->numBuckets);

  int pos = VectorSearch(&h->vectorArray[hash], elemAddr, h->cmpFunc, 0, false);
  if (pos == -1)
	  VectorAppend(&h->vectorArray[hash], elemAddr);
  else
	  VectorReplace(&h->vectorArray[hash], elemAddr, pos);
}

void *HashSetLookup(const hashset *h, const void *elemAddr)
{ 
  assert(elemAddr != NULL);  
  int hash = h->hashFunc(elemAddr, h->numBuckets);
  assert(hash >= 0 && hash < h->numBuckets);

  int pos = VectorSearch(&h->vectorArray[hash], elemAddr, h->cmpFunc, 0, false);
  if (pos != -1)
	  return VectorNth(&h->vectorArray[hash], pos);

  return NULL; 
}
